•Backend
redis与mysql 的数据一致性如何保证?
如何保证Redis与Mysql的数据一致性?
RedisMySQL
如何保证Redis与Mysql的数据一致性?
常见的方案有这么几种:
- 先改数据库,再改缓存
- 先改缓存,再改数据库
- 先删除缓存,再修改数据库
- 先修改数据库,再删缓存
- 延迟双删策略,先删除缓存,再修改数据库,再删除缓存
- 使用 Binlog 异步更新缓存,监听数据库的 Binlog 变化,通过异步方式更新 Redis 缓存
以上六种实现方式中,前三种一般都不推荐。实际项目开发中用的最多的是第四种和第五种。
这是因为四五的逻辑清晰,且实现简单,并且在绝大多数场景下都能保证数据最终一致性,只会短暂导致数据不一致的场景。但绝大多数场景下,并不要求数据强一致性。而且第六种方案,实现复杂,并且还需要长期对他进行维护,增加额外的维护成本。所以在大多数场景下,第四和第五种方案已经够用了。
先改数据库,再改缓存/ 先改缓存,再改数据库
无论是先修改数据库还是先修改缓存,这两种方案都有一个问题就是:由于可能的网络波动和并发问题,导致请求可能无法顺序执行,请求A和请求B都想要去更新数据,但最后的结果可能是请求A的两步操作中穿插了请求B,或请求B中穿插了请求A。导致数据不一致
先删除缓存再写数据库
他的问题在于:
- 请求 A 先对缓存中的数据进行删除操作。
- 请求 B 这个时候来执行查询,发现缓存中数据为空,就去数据库进行查询并回写缓存。
- 请求 A 进行数据库数据的更新。
- 请求 B 已经把从数据库查询到的原始数据回写缓存了。导致了数据不一致
缓存双删(先删除缓存,再写数据库,然后过一段时间再删除缓存)
这个方案为了避免旧数据被回种,等待一段时间后再延迟删除缓存。
也可以使用消息队列、定时任务或者延迟任务等方式去实现延迟删除
先写数据库,再删除缓存
他的问题在于:
- 请求B查询缓存为空,然后去查询数据库
- 请求A更新数据库,并删除缓存
- 请求B将数据库查询的值回写到缓存
其主要原因在于有一个写操作,此时刚好缓存失效,又在同一时刻刚好有一个并发读请求过来,且回写缓存的请求晚于缓存删除,导致数据库与缓存的不一致。
从上面的表述可以知道,这个发生的概率比较低,一般而言业务上都会使用这个方案。